{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fTFj8ft5dlbS"
      },
      "source": [
        "##### Copyright 2018 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "lzyBOpYMdp3F"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "m_x4KfSJ7Vt7"
      },
      "outputs": [],
      "source": [
        "#@title MIT License\n",
        "#\n",
        "# Copyright (c) 2017 François Chollet\n",
        "#\n",
        "# Permission is hereby granted, free of charge, to any person obtaining a\n",
        "# copy of this software and associated documentation files (the \"Software\"),\n",
        "# to deal in the Software without restriction, including without limitation\n",
        "# the rights to use, copy, modify, merge, publish, distribute, sublicense,\n",
        "# and/or sell copies of the Software, and to permit persons to whom the\n",
        "# Software is furnished to do so, subject to the following conditions:\n",
        "#\n",
        "# The above copyright notice and this permission notice shall be included in\n",
        "# all copies or substantial portions of the Software.\n",
        "#\n",
        "# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n",
        "# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n",
        "# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n",
        "# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n",
        "# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n",
        "# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n",
        "# DEALINGS IN THE SOFTWARE."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "C9HmC2T4ld5B"
      },
      "source": [
        "# Sovradattamento e sottoadattamento"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kRTxFhXAlnl1"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://www.tensorflow.org/tutorials/keras/overfit_and_underfit\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" />Visualizza su TensorFlow.org</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/it/tutorials/keras/overfit_and_underfit.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />Esegui in Google Colab</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/it/tutorials/keras/overfit_and_underfit.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />Visualizza il sorgente su GitHub</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/it/tutorials/keras/overfit_and_underfit.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\" />Scarica il notebook</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "BYzaKBe8YXg0"
      },
      "source": [
        "Note: La nostra comunità di Tensorflow ha tradotto questi documenti. Poichè queste traduzioni sono *best-effort*, non è garantito che rispecchino in maniera precisa e aggiornata la [documentazione ufficiale in inglese](https://www.tensorflow.org/?hl=en). \n",
        "Se avete suggerimenti per migliorare questa traduzione, mandate per favore una pull request al repository Github [tensorflow/docs](https://github.com/tensorflow/docs). \n",
        "Per proporsi come volontari alla scrittura o alla review delle traduzioni della comunità contattate la \n",
        "[mailing list docs@tensorflow.org](https://groups.google.com/a/tensorflow.org/forum/#!forum/docs)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "19rPukKZsPG6"
      },
      "source": [
        "Come sempre, il codice in questo esempio usa le API `tf.keras`, di cui potete imparare di più nella [guida Keras](https://www.tensorflow.org/guide/keras) di TensorFlow.\n",
        "\n",
        "In entrambi gli esempi precedenti—[classificazione di testo](https://www.tensorflow.org/tutorials/keras/text_classification_with_hub) e [previsione di consumo carburante](https://www.tensorflow.org/tutorials/keras/regression) — abbiamo visto come l'accuratezza del nostro modello sui dati di validazione raggiunga il picco dopo l'addestramento per un certo numero di epoche, e poi ristagni o cominci a decrescere.\n",
        "\n",
        "In altre parole, come il nostro modello si *sovradatti* (*overfit* n.d.t.) con i dati addestramento. Imparare come gestire il sovradattamento è importante. Sebbene sia spesso possibile raggiungere un'accuratezza alta sul *insieme di addestramento*, ciò che realmente vogliamo è sviluppare un modello che generalizzi bene sul *insieme di test* (o su dati che non ha mai visto prima).\n",
        "\n",
        "L'opposto del sovradattamento è il *sottoadattamento*. Il sottoadattamento si verifica quando c'è ancora spazio di miglioramento sui dati di test. Ciò può accadere per un certo numero di ragioni: Se il modello non è abbastanza potente, se è sovra-regolarizzato, o, semplicemente, non è stato addestrato abbastanza. Ciò significa che la rete non ha appreso i pattern rilevanti nei dati di addestramento.\n",
        "\n",
        "Se lo allenate per un tempo troppo lungo, il modello inizierà a sovradattarsi ed ad imparare pattern dai dati di addestramento che non si generalizzeranno ai dati di test. Dobbiamo trovare un compromesso. Capire come addestrare per un numero appropriato di epoche, come vedremo nel seguito, è una competenza utile.\n",
        "\n",
        "La soluzione migliore per prevenire il sovradattaemnto è usare dati di addestramento più completi. Il dataset dovrebbe coprire lo spettro completo degli input che il modello possa aspettarsi di trattare. Ulteriori dati possono essere utili solo se coprono nuovi ed interessanti casi.\n",
        "\n",
        "Un modello addestrato su un insieme più completo di dati generalizzerà naturalmente meglio. Quando ciò non fosse possibile, la soluzione migliore è usare tecniche come la regolarizzazione. Esse impongono dei vincoli alla quantità ed al tipo di informazioni che il vostro modello può immagazzinare. Se una rete può memorizzare solo un piccolo numero di pattern, il processo di ottimizzazione lo costringerà a focalizzarsi sui patern più promettenti, che hanno la migliore probabilità di generalizzare bene.\n",
        "\n",
        "In questo notebook, esploreremo diverse tecniche di regolarizzazione, e le useremo per migliorare un modello di classificazione."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "WL8UoOTmGGsL"
      },
      "source": [
        "## Setup"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9FklhSI0Gg9R"
      },
      "source": [
        "Prima di iniziare,importiamo i pacchetti necessari:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "5pZ8A2liqvgk"
      },
      "outputs": [],
      "source": [
        "from __future__ import absolute_import, division, print_function, unicode_literals\n",
        "\n",
        "try:\n",
        "  # %tensorflow_version only exists in Colab.\n",
        "  %tensorflow_version 2.x\n",
        "except Exception:\n",
        "  pass\n",
        "import tensorflow as tf\n",
        "\n",
        "from tensorflow.keras import layers\n",
        "from tensorflow.keras import regularizers\n",
        "\n",
        "print(tf.__version__)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "QnAtAjqRYVXe"
      },
      "outputs": [],
      "source": [
        "!pip install git+https://github.com/tensorflow/docs\n",
        "\n",
        "import tensorflow_docs as tfdocs\n",
        "import tensorflow_docs.modeling\n",
        "import tensorflow_docs.plots"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "-pnOU-ctX27Q"
      },
      "outputs": [],
      "source": [
        "from  IPython import display\n",
        "from matplotlib import pyplot as plt\n",
        "\n",
        "import numpy as np\n",
        "\n",
        "import pathlib\n",
        "import shutil\n",
        "import tempfile\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "jj6I4dvTtbUe"
      },
      "outputs": [],
      "source": [
        "logdir = pathlib.Path(tempfile.mkdtemp())/\"tensorboard_logs\"\n",
        "shutil.rmtree(logdir, ignore_errors=True)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1cweoTiruj8O"
      },
      "source": [
        "## Il dataset Higgs\n",
        "\n",
        "L'obiettivo di questo tutorial non è fare fisica delle particelle, perciò non approfondiamo i dettagli del dataset. Esso contiene  11&#x202F;000&#x202F;000 esempi, con 28 caratteristiche ciascuno, ed una etichetta di classificazione binaria."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "YPjAvwb-6dFd"
      },
      "outputs": [],
      "source": [
        "gz = tf.keras.utils.get_file('HIGGS.csv.gz', 'https://archive.ics.uci.edu/ml/machine-learning-databases/00280/HIGGS.csv.gz')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "AkiyUdaWIrww"
      },
      "outputs": [],
      "source": [
        "FEATURES = 28"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SFggl9gYKKRJ"
      },
      "source": [
        "La classe `tf.data.experimental.CsvDataset` può essere usata per leggere record csv direttamente da un file gzip senza passi intermedi di decompressione."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "QHz4sLVQEVIU"
      },
      "outputs": [],
      "source": [
        "ds = tf.data.experimental.CsvDataset(gz,[float(),]*(FEATURES+1), compression_type=\"GZIP\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HzahEELTKlSV"
      },
      "source": [
        "La classe che legge il cvs restituisce una lista di scalari per ogni record. La funzione seguente re-impacchetta tale lista in una coppia (vettore_di_caratteristiche, etichetta)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "zPD6ICDlF6Wf"
      },
      "outputs": [],
      "source": [
        "def pack_row(*row):\n",
        "  label = row[0]\n",
        "  features = tf.stack(row[1:],1)\n",
        "  return features, label"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4oa8tLuwLsbO"
      },
      "source": [
        "TensorFlow è più efficiente quando tratta grandi lotti di dati.\n",
        "\n",
        "Così, invece di re-impacchettare ciascuna riga individualmente, costruiamo un nuovo `Dataset` che contiene lotti di 10000-esempi, applichiamo la funzione `pack_row` a ciascun lotto, e quindi separiamo i lotti in singoli record:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "-w-VHTwwGVoZ"
      },
      "outputs": [],
      "source": [
        "packed_ds = ds.batch(10000).map(pack_row).unbatch()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lUbxc5bxNSXV"
      },
      "source": [
        "Diamo uno sguardo ad alcuni dei record di questo nuovo `packed_ds`.\n",
        "\n",
        "Le caratteristiche non sono perfettamente normalizzate, ma questo non è un problema per questo tutorial."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "TfcXuv33Fvka"
      },
      "outputs": [],
      "source": [
        "for features,label in packed_ds.batch(1000).take(1):\n",
        "  print(features[0])\n",
        "  plt.hist(features.numpy().flatten(), bins = 101)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ICKZRY7gN-QM"
      },
      "source": [
        "Per mantenere questo tutorial relativamente breve, usiamo solo i primi 1000 campioni per la validazione, ed i successivi 10000 per l'addestramento:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "hmk49OqZIFZP"
      },
      "outputs": [],
      "source": [
        "N_VALIDATION = int(1e3)\n",
        "N_TRAIN = int(1e4)\n",
        "BUFFER_SIZE = int(1e4)\n",
        "BATCH_SIZE = 500\n",
        "STEPS_PER_EPOCH = N_TRAIN//BATCH_SIZE"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FP3M9DmvON32"
      },
      "source": [
        "I metodi `Dataset.skip` e `Dataset.take` rendono semplice la cosa.\n",
        "\n",
        "Allo stesso tempo, usare il metodo `Dataset.cache` assicura che il caricatore non abbia bisogno di ri-leggerei dati dal file ad ogni nuova epoca:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "H8H_ZzpBOOk-"
      },
      "outputs": [],
      "source": [
        "validate_ds = packed_ds.take(N_VALIDATION).cache()\n",
        "train_ds = packed_ds.skip(N_VALIDATION).take(N_TRAIN).cache()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "9zAOqk2_Px7K"
      },
      "outputs": [],
      "source": [
        "train_ds"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6PMliHoVO3OL"
      },
      "source": [
        "Questi dataset restituiscono esempi singoli. Usiamo il metodo `.batch` per creare lotti di dimensione appropriata per l'addestramento. Prima della confezione dei lotti ricordiamo anche di `.shuffle` (*mescolare* n.d.t.) e `.repeat` (*ripetere* n.d.t.) l'insieme di addestramento."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Y7I4J355O223"
      },
      "outputs": [],
      "source": [
        "validate_ds = validate_ds.batch(BATCH_SIZE)\n",
        "train_ds = train_ds.shuffle(BUFFER_SIZE).repeat().batch(BATCH_SIZE)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lglk41MwvU5o"
      },
      "source": [
        "## Dimostrazione di sovradattamento\n",
        "\n",
        "La via più semplice per prevenire il sovradattamento è cominciare con un modello piccolo: un modello con un piccolo numero di parametri da apprendere (determinati dal numero di livelli e dal numero di unità per livello). Nel deep learning, spesso si fa riferimento al numero di parametri che possono essere appresi da un modello, come la \"capacity\" del modello.\n",
        "\n",
        "Intuitivamente, un modello con più parametri avrà maggiore \"capacità di memorizzazione\" e quindi sarà capace di imparare facilmente una corrispondenza perfetta simil-vocabolario tra i campioni di addestramento ed i relativi obiettivi, una mappatura senza nessun potere di generalizzazione, ma ciò sarebbe inutile per fare previsioni su dati mai visti.\n",
        "\n",
        "Teniamo sempre a mente: i modelli di deep learning tendono ad essere bravi nell'aderire ai dati di addestramneto, ma la sfida reale è la generalizzazione, non l'adattamento.\n",
        "\n",
        "d'altra parte, se la rete ha limitate risorse di memorizzazione, non sarà capace di imparare la mappatura così facilmente. Per minimizzare la sua funzione obiettivo, dovrà apprendere rappresentazioni compresse che hanno maggiore potere predittivo. Allo stesso tempo, se fate il vostro modello troppo piccolo, esso ha difficoltà ad aderire ai dati di addestramento. Occorre trovare un punto di equilibrio tra \"capacità eccessiva\" e \"capacità insufficiente\".\n",
        "\n",
        "Sfortunatamente, non c'è nessuna formula magica per stabilire la dimensione giusta o l'architettura del vostro modello (in altre parole, il numero dei livelli, o la dimensione giusta di ciascun livello). Dovrete fare esperimenti usando architetture diverse.\n",
        "\n",
        "Per trovare la dimensione giusta del modello, è meglio partire con relativamente pochi livelli e parametri, quindi cominciare ad aumentare la dimensione dei livelli o ad aggiungere nuovi livelli fino a che non vedete diminuire gli effetti sulla funzione obiettivo di validazione.\n",
        "\n",
        "Come punto di partenza, iniziate con un modello semplice che usa solo `layers.Dense`, poi create versioni più grandi e confrontatele."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_ReKHdC2EgVu"
      },
      "source": [
        "### Procedura di addestramento"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "pNzkSkkXSP5l"
      },
      "source": [
        "Molti modelli si addestrano meglio se riducete gradualmente il tasso di apprendimento durante l'addestramento. Per ridurre il tasso di apprendimento nel tempo, usiamo `optimizers.schedules`:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "LwQp-ERhAD6F"
      },
      "outputs": [],
      "source": [
        "lr_schedule = tf.keras.optimizers.schedules.InverseTimeDecay(\n",
        "  0.001,\n",
        "  decay_steps=STEPS_PER_EPOCH*1000,\n",
        "  decay_rate=1,\n",
        "  staircase=False)\n",
        "\n",
        "def get_optimizer():\n",
        "  return tf.keras.optimizers.Adam(lr_schedule)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kANLx6OYTQ8B"
      },
      "source": [
        "Il codice di cui sopra usa `schedules.InverseTimeDecay` per diminuire iperbolicamente il tasso di apprendimento ad 1/2 del tasso base dopo 1000 epoche, ad 1/3 a 2000 epoche e così via."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "HIo_yPjEAFgn"
      },
      "outputs": [],
      "source": [
        "step = np.linspace(0,100000)\n",
        "lr = lr_schedule(step)\n",
        "plt.figure(figsize = (8,6))\n",
        "plt.plot(step/STEPS_PER_EPOCH, lr)\n",
        "plt.ylim([0,max(plt.ylim())])\n",
        "plt.xlabel('Epoch')\n",
        "_ = plt.ylabel('Learning Rate')\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ya7x7gr9UjU0"
      },
      "source": [
        "Ogni modello in questo tutorial userà la medesima configurazione di addestramento. Perciò la impostiamo in modo riusabile, partendo dalla lista delle callback.\n",
        "\n",
        "L'addestramento di questo tutorial gira per molte epoche brevi. Per ridurre lo sforzo di tracciamento usiamo `tfdocs.EpochDots` che utilizza un semplice `.` per ogni epoca e, un insieme completo di metriche ogni 100 epoche.\n",
        "\n",
        "In seguito, includiamo `callbacks.EarlyStopping` per evitare lunghi tempi di addestramento non necessari. notate che questa callback è impostata per monitorare la `val_binary_crossentropy`, non la `val_loss`. Questa differenza sarà importante in seguito.\n",
        "\n",
        "Usiamo `callbacks.TensorBoard` per generare i tracciati TensorBoard per l'addestramento.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "vSv8rfw_T85n"
      },
      "outputs": [],
      "source": [
        "def get_callbacks(name):\n",
        "  return [\n",
        "    tfdocs.modeling.EpochDots(),\n",
        "    tf.keras.callbacks.EarlyStopping(monitor='val_binary_crossentropy', patience=200),\n",
        "    tf.keras.callbacks.TensorBoard(logdir/name),\n",
        "  ]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "VhctzKhBWVDD"
      },
      "source": [
        "Analogamente, ogni modello userà le stesse impostazioni `Model.compile` e `Model.fit` settings:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "xRCGwU3YH5sT"
      },
      "outputs": [],
      "source": [
        "def compile_and_fit(model, name, optimizer=None, max_epochs=10000):\n",
        "  if optimizer is None:\n",
        "    optimizer = get_optimizer()\n",
        "  model.compile(optimizer=optimizer,\n",
        "                loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),\n",
        "                metrics=[\n",
        "                  tf.keras.losses.BinaryCrossentropy(\n",
        "                      from_logits=True, name='binary_crossentropy'),\n",
        "                  'accuracy'])\n",
        "\n",
        "  model.summary()\n",
        "\n",
        "  history = model.fit(\n",
        "    train_ds,\n",
        "    steps_per_epoch = STEPS_PER_EPOCH,\n",
        "    epochs=max_epochs,\n",
        "    validation_data=validate_ds,\n",
        "    callbacks=get_callbacks(name),\n",
        "    verbose=0)\n",
        "  return history"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mxBeiLUiWHJV"
      },
      "source": [
        "### Modello minuscolo"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "a6JDv12scLTI"
      },
      "source": [
        "Iniziamo addestrando un modello lineare:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "EZh-QFjKHb70"
      },
      "outputs": [],
      "source": [
        "tiny_model = tf.keras.Sequential([\n",
        "    layers.Dense(16, activation='elu', input_shape=(FEATURES,)),\n",
        "    layers.Dense(1)\n",
        "])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "X72IUdWYipIS"
      },
      "outputs": [],
      "source": [
        "size_histories = {}"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "bdOcJtPGHhJ5"
      },
      "outputs": [],
      "source": [
        "size_histories['Tiny'] = compile_and_fit(tiny_model, 'sizes/Tiny')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rS_QGT6icwdI"
      },
      "source": [
        "Adesso controlliamo cos'ha fatto il modello:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "dkEvb2x5XsjE"
      },
      "outputs": [],
      "source": [
        "plotter = tfdocs.plots.HistoryPlotter(metric = 'binary_crossentropy', smoothing_std=10)\n",
        "plotter.plot(size_histories)\n",
        "plt.ylim([0.5, 0.7])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LGxGzh_FWOJ8"
      },
      "source": [
        "### Modello piccolo"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YjMb6E72f2pN"
      },
      "source": [
        "Per vedere se possiamo battere le prestazioni del modello piccolo, addestriamo progressivamente modelli più grandi.\n",
        "\n",
        "Proviamo due livelli nascosti con 16 unità ciascuno:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "QKgdXPx9usBa"
      },
      "outputs": [],
      "source": [
        "small_model = tf.keras.Sequential([\n",
        "    # `input_shape` is only required here so that `.summary` works.\n",
        "    layers.Dense(16, activation='elu', input_shape=(FEATURES,)),\n",
        "    layers.Dense(16, activation='elu'),\n",
        "    layers.Dense(1)\n",
        "])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "LqG3MXF5xSjR"
      },
      "outputs": [],
      "source": [
        "size_histories['Small'] = compile_and_fit(small_model, 'sizes/Small')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "L-DGRBbGxI6G"
      },
      "source": [
        "### Modello medio"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SrfoVQheYSO5"
      },
      "source": [
        "Ora proviamo 3 modelli nascosti con 64 unità ciascuno:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "jksi-XtaxDAh"
      },
      "outputs": [],
      "source": [
        "medium_model = tf.keras.Sequential([\n",
        "    layers.Dense(64, activation='elu', input_shape=(FEATURES,)),\n",
        "    layers.Dense(64, activation='elu'),\n",
        "    layers.Dense(64, activation='elu'),\n",
        "    layers.Dense(1)\n",
        "])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jbngCZliYdma"
      },
      "source": [
        "Ed addestriamo il modello usando i medesimi dati:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Ofn1AwDhx-Fe"
      },
      "outputs": [],
      "source": [
        "size_histories['Medium']  = compile_and_fit(medium_model, \"sizes/Medium\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vIPuf23FFaVn"
      },
      "source": [
        "### Modello grande\n",
        "\n",
        "Come esercizio, potete creare un modello ancora più grande, e vedere come comincia a sovradattarsi rapidamente.  Poi, aggiungiamo a questa prova una rete con capacità ancora maggiore, molto più di quanto il problema richiederebbe:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ghQwwqwqvQM9"
      },
      "outputs": [],
      "source": [
        "large_model = tf.keras.Sequential([\n",
        "    layers.Dense(512, activation='elu', input_shape=(FEATURES,)),\n",
        "    layers.Dense(512, activation='elu'),\n",
        "    layers.Dense(512, activation='elu'),\n",
        "    layers.Dense(512, activation='elu'),\n",
        "    layers.Dense(1)\n",
        "])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "D-d-i5DaYmr7"
      },
      "source": [
        "E ancora, addestrare il modello usando gli stessi dati:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "U1A99dhqvepf"
      },
      "outputs": [],
      "source": [
        "size_histories['large'] = compile_and_fit(large_model, \"sizes/large\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Fy3CMUZpzH3d"
      },
      "source": [
        "### Traccia delle funzioni obiettivo in addestramento e validazione"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HSlo1F4xHuuM"
      },
      "source": [
        "Le linee continue mostrano la funzione obiettivo in addestramento, e le linee tratteggiate la funzione obiettivo in validazione (ricordate: una minore funzione obiettivo in validazione indica un modello migliore)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "OLhL1AszdLfM"
      },
      "source": [
        "Mentre la costruzione di un modello più grande gli conferisce più potenza, se questa potenza non è vincolata in qualche modo, essa può facilmente sovradattarsi sull'insieme di addestramento.\n",
        "\n",
        "In questo esempio, tipicamente, solo il modello `\"Minuscolo\"` riesce ad evitare completamente il sovradattamento, mentre ciascuno dei modelli più grandi si sovradatta ai dati più rapidamente. Ciò diventa così grave oer il modello `\"grande\"` che siamo costretti a modificare il grafico ad una scala logaritmica per vedere ciò che realmente accade.\n",
        "\n",
        "La cosa è evidente se si tracciano e confrontano le metriche di validazione e le metriche di addestramento.\n",
        "\n",
        "* E' normale ci sia una piccola differenza.\n",
        "* Se entrambe le metriche si muovono nella stessa direzione, va tutto bene.\n",
        "* Se la metrica di validazione comincia a ristagnare mentre la metrica di addestramento continua a migliorare, siamo probabilmente vicini al sovradattamento.\n",
        "* Se la metrica di validazione va nella direzione sbagliata, il modello si sta chiaramente sovradattando."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "0XmKDtOWzOpk"
      },
      "outputs": [],
      "source": [
        "plotter.plot(size_histories)\n",
        "a = plt.xscale('log')\n",
        "plt.xlim([5, max(plt.xlim())])\n",
        "plt.ylim([0.5, 0.7])\n",
        "plt.xlabel(\"Epochs [Log Scale]\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "UekcaQdmZxnW"
      },
      "source": [
        "Notare: tutti gli addestramenti precedenti girano usando `callbacks.EarlyStopping` per fermare l'addestramento una volta che sia chiaro che il modello non stia facendo progressi."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DEQNKadHA0M3"
      },
      "source": [
        "### Visualizzazione in TensorBoard\n",
        "\n",
        "Tutti questi modelli scrivono tracciati TensorBoard durante l'addestramento.\n",
        "\n",
        "Per aprire un visualizzatore TensorBoard all'interno di un notebook, copiate il codice seguente in una code-cell:\n",
        "\n",
        "```\n",
        "%tensorboard --logdir {logdir}/sizes\n",
        "```"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fjqx3bywDPjf"
      },
      "source": [
        "Possiamo vedere il [risultato di un'esecuzione precedente](https://tensorboard.dev/experiment/vW7jmmF9TmKmy3rbheMQpw/#scalars&_smoothingWeight=0.97) di questo notebook su [TensorBoard.dev](https://tensorboard.dev/).\n",
        "\n",
        "TensorBoard.dev è un ambiente gestito per ospitare, tracciare e condividere con chiunque esperimenti di ML.\n",
        "\n",
        "Per semplicità, è anche incluso in un `<iframe>`:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "dX5fcgrADwym"
      },
      "outputs": [],
      "source": [
        "display.IFrame(\n",
        "    src=\"https://tensorboard.dev/experiment/vW7jmmF9TmKmy3rbheMQpw/#scalars&_smoothingWeight=0.97\",\n",
        "    width=\"100%\", height=\"800px\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "RDQDBKYZBXF_"
      },
      "source": [
        "Se vogliamo condividere risultati TensorBoard, possiamo caricare i tracciati in [TensorBoard.dev](https://tensorboard.dev/) copiando il codice seguente in una code-cell.\n",
        "\n",
        "Notare: Questo passo richiede un account Google.\n",
        "\n",
        "```\n",
        "!tensorboard dev upload --logdir  {logdir}/sizes\n",
        "```\n",
        "\n",
        "Attenzione: Questo comando non termina. E' progettato per eseguire l'upload continuo dei risultati di un esperimento di lunga durata. Una volta che i nostri dati sono caricati lo dovete fermare usando l'opzione \"interrupt execution (interrompi l'esecuzione n.d.t.)\" nel vostro strumento di esecuzione dei notebook."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ASdv7nsgEFhx"
      },
      "source": [
        "## Strategie per prevenire il sovradattamento"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YN512ksslaxJ"
      },
      "source": [
        "Prima di andare all'interno del contenuto di questo paragrafo, copiamo i tracciati dell'addestramento del modello `\"Minuscolo\"` di cui sopra, per usarlo come termine di paragone."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "40k1eBtnQzNo"
      },
      "outputs": [],
      "source": [
        "shutil.rmtree(logdir/'regularizers/Tiny', ignore_errors=True)\n",
        "shutil.copytree(logdir/'sizes/Tiny', logdir/'regularizers/Tiny')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "vFWMeFo7jLpN"
      },
      "outputs": [],
      "source": [
        "regularizer_histories = {}\n",
        "regularizer_histories['Tiny'] = size_histories['Tiny']"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4rHoVWcswFLa"
      },
      "source": [
        "### Aggiunta della regolarizzazione del peso\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kRxWepNawbBK"
      },
      "source": [
        "Potreste avere familiarità con il principio del Rasoio di Occam: date due spiegazioni per qualcosa, la spiegazione che ha più probabilità di essere corretta è la \"più semplice\", quella che fa meno ipotesi. Ciò si applica anche ai modelli appresi dalle reti neurali: dato un insieme di dati di addestramento ed un'architettura di rete, ci sono molteplici insiemi di valori dei pesi (molteplici modelli) che possono spiegare i dati, ed i modelli più semplici si sovradattano meno facilmente di quelli complessi.\n",
        "\n",
        "In questo contesto, un \"modello semplice\" è un modello in cui la distribuzione dei valori dei parametri ha meno entropia (o un modello con meno parametri del tutto, come vediamo del paragrafo sopra). Così, un modo comune di mitigare il sovradattamento è porre dei vincoli alla complessità di una rete forzando i suoi pesi a prendere solo valori piccoli, il che rende la distribuzione dei valori dei pesi \"regolare\". Ciò è chiamato \"regolarizzazione dei pesi\", e lo si fa aggiungendo alla funzione dei pesi della rete un costo associato all'avere grandi pesi. Questo costo è di due tipi:\n",
        "\n",
        "* [Regolarizzazione L1](https://developers.google.com/machine-learning/glossary/#L1_regularization), in cui il costo aggiunto è proporzionale al valore assoluto dei coefficienti dei pesi (cioè a ciò che viene chiamata \"norma L1\" dei pesi).\n",
        "\n",
        "* [regolarizzazione L2](https://developers.google.com/machine-learning/glossary/#L2_regularization), in cui il costo aggiunto è proporzionale al quadrato dei coefficienti dei pesi (cioè a quella che è chiamata \"norma L2\" dei pesi). Nel contesto delle reti neurali, la regolarizzazione L2 è chiamata anche decadimento dei pesi. Non lasciate che il nome vi confonda: il decadimento dei pesi è matematicamente la regolarizzazione L2.\n",
        "\n",
        "La regolarizzazione L1spinge i pesi esattamente verso lo zero, favorendo un modello sparso. La regolarizzazione L2 penalizzerà i parametri di peso senza renderli sparsi in quanto la penalità tende a zero per pesi piccoli. La ragione per cui L2 è più comune.\n",
        "\n",
        "In `tf.keras`, la regolarizzazione del peso viene ottenuta passando ai livelli delle istanze di regolarizzazione del peso come argomenti delle parole chiave. Ora andiamo ad aggiungere la regolarizzazione L2."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "HFGmcwduwVyQ"
      },
      "outputs": [],
      "source": [
        "l2_model = tf.keras.Sequential([\n",
        "    layers.Dense(512, activation='elu',\n",
        "                 kernel_regularizer=regularizers.l2(0.001),\n",
        "                 input_shape=(FEATURES,)),\n",
        "    layers.Dense(512, activation='elu',\n",
        "                 kernel_regularizer=regularizers.l2(0.001)),\n",
        "    layers.Dense(512, activation='elu',\n",
        "                 kernel_regularizer=regularizers.l2(0.001)),\n",
        "    layers.Dense(512, activation='elu',\n",
        "                 kernel_regularizer=regularizers.l2(0.001)),\n",
        "    layers.Dense(1)\n",
        "])\n",
        "\n",
        "regularizer_histories['l2'] = compile_and_fit(l2_model, \"regularizers/l2\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bUUHoXb7w-_C"
      },
      "source": [
        "`l2(0.001)` significa che ogni coefficiente nella matrice dei pesi del livello aggiunge `0.001 * weight_coefficient_value**2` al totale **loss** della rete.\n",
        "\n",
        "Questo è il perché monitoriamo direttamente il `binary_crossentropy`. Perché non ha mescolata in se questa componente di regolarizzazione.\n",
        "\n",
        "Così, lo stesso modello `\"Grande\"` con una regolarizzazione di penalità `L2` ha migliori prestazioni:\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "7wkfLyxBZdh_"
      },
      "outputs": [],
      "source": [
        "plotter.plot(regularizer_histories)\n",
        "plt.ylim([0.5, 0.7])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Kx1YHMsVxWjP"
      },
      "source": [
        "Come potete vedere, il modello `\"L2\"`-regolarizzato è ora molto più competitivo con il modello `\"Minuscolo\"`. Questo modello `\"L2\"` è anche molto più resistente al sovradattamento del modello `\"Grande\"` su cui si basava pur avendo lo stesso numero di parametri."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "JheBk6f8jMQ7"
      },
      "source": [
        "#### Maggiori informazioni\n",
        "\n",
        "Ci sono due cose importanti da notare a proposito di questo tipo di regolarizzazione.\n",
        "\n",
        "**Primo:** se state scrivendo il vostro proprio ciclo di addestramento, allora dovete essere sicuri di chiedere al modello le sue perdite di regolarizzazione."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "apDHQNybjaML"
      },
      "outputs": [],
      "source": [
        "result = l2_model(features)\n",
        "regularization_loss=tf.add_n(l2_model.losses)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MLhG6fMSjE-J"
      },
      "source": [
        "**Secondo:** Questa implementazione funziona aggiungendo le penalizzazioni di peso alla funzione obiettivo del modello, e poi applicando una procedura di ottimizzazione standard.\n",
        "\n",
        "C'è un secondo approccio che applica invece l'ottimizzatore sulla funzione obiettivo grezza, e poi mentre applica il passo calcolato, l'ottimizzatore applica anche un decadimento di peso. Questo \"Decadimento di Peso Disaccoppiato\" viene visto in ottimizzatori come `optimizers.FTRL` e `optimizers.AdamW`."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HmnBNOOVxiG8"
      },
      "source": [
        "### Aggiunta di un dropout\n",
        "\n",
        "Il dropout (\"punto di rinuncia\" n.d.t.) è una delle tecniche di regolarizzazione più efficaci e più comunemente utilizzate per le reti neurali, sviluppata da Hinton ed i suoi studenti all'università di Toronto.\n",
        "\n",
        "Una spiegazione intuitiva per il dropout è che: in virtù del fatto che i singoli nodi della rete non possono fare affidamento sull'output degli altri, ciascun nodo deve produrre caratteristiche di output utili in se stesse.\n",
        "\n",
        "Il dropout, applicato ad un livello, consiste nel \"dropping out (far decadere n.d.t.)\" (cioè impostare a zero) un certo numero di caratteristiche di output del livello, durante l'addestramento. Supponiamo che un dato livello, normalmente, durante l'addestramento, restituisca un vettore [0.2, 0.5, 1.3, 0.8, 1.1] per un dato campione di input; dopo l'applicazione del dropout, questo vettore avrà alcuni valori a zero distribuiti casualmente, es: [0, 0.5,\n",
        "1.3, 0, 1.1].\n",
        "\n",
        "Il \"tasso di dropout\" è la frazione delle caratteristiche azzerate; di solito si fissa tra 0.2 e 0.5. Durante il test, non ci sono unità azzerate, ed invece i valori di uscita del livello sono scalati in basso di un fattore uguale al tasso di dropout, per bilanciare il fatto che ci sono più unità attive che durante l'addestramento.\n",
        "\n",
        "In `tf.keras` potete inserire il dropout in una rete per mezzo di un livello Dropout, che viene applicato all'output el livello immediatamente precedente.\n",
        "\n",
        "Aggiungiamo due livelli Dropout nella nostra rete per vedere quanto bene riducano il sovradattamento:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "OFEYvtrHxSWS"
      },
      "outputs": [],
      "source": [
        "dropout_model = tf.keras.Sequential([\n",
        "    layers.Dense(512, activation='elu', input_shape=(FEATURES,)),\n",
        "    layers.Dropout(0.5),\n",
        "    layers.Dense(512, activation='elu'),\n",
        "    layers.Dropout(0.5),\n",
        "    layers.Dense(512, activation='elu'),\n",
        "    layers.Dropout(0.5),\n",
        "    layers.Dense(512, activation='elu'),\n",
        "    layers.Dropout(0.5),\n",
        "    layers.Dense(1)\n",
        "])\n",
        "\n",
        "regularizer_histories['dropout'] = compile_and_fit(dropout_model, \"regularizers/dropout\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "SPZqwVchx5xp"
      },
      "outputs": [],
      "source": [
        "plotter.plot(regularizer_histories)\n",
        "plt.ylim([0.5, 0.7])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4zlHr4iaI1U6"
      },
      "source": [
        "E' chiaro da questo grafico che entrambi questi approcci di regolarizzazione migliorano il comportamento del modello `\"Grande\"`. Ma non reggono ancora il confronto con il `\"Minuscolo\"`.\n",
        "\n",
        "Nel seguito li proviamo, tutti e due insieme, e vediamo se fanno di meglio."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "u7qMg_7Nwy5t"
      },
      "source": [
        "### Dropout combinati L1 + L2"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "7zfs_qQIw1cz"
      },
      "outputs": [],
      "source": [
        "combined_model = tf.keras.Sequential([\n",
        "    layers.Dense(512, kernel_regularizer=regularizers.l2(0.0001),\n",
        "                 activation='elu', input_shape=(FEATURES,)),\n",
        "    layers.Dropout(0.5),\n",
        "    layers.Dense(512, kernel_regularizer=regularizers.l2(0.0001),\n",
        "                 activation='elu'),\n",
        "    layers.Dropout(0.5),\n",
        "    layers.Dense(512, kernel_regularizer=regularizers.l2(0.0001),\n",
        "                 activation='elu'),\n",
        "    layers.Dropout(0.5),\n",
        "    layers.Dense(512, kernel_regularizer=regularizers.l2(0.0001),\n",
        "                 activation='elu'),\n",
        "    layers.Dropout(0.5),\n",
        "    layers.Dense(1)\n",
        "])\n",
        "\n",
        "regularizer_histories['combined'] = compile_and_fit(combined_model, \"regularizers/combined\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "qDqBBxfI0Yd8"
      },
      "outputs": [],
      "source": [
        "plotter.plot(regularizer_histories)\n",
        "plt.ylim([0.5, 0.7])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "tE0OoNCQNTJv"
      },
      "source": [
        "Questo modello con la regolarizzazione `\"Combinata\"` è ovviamente, fin'ora, il migliore."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-dw23T03FEO1"
      },
      "source": [
        "### Visualizzazione in TensorBoard\n",
        "\n",
        "Anche questi modelli registrano tracciati TensorBoard.\n",
        "\n",
        "Per aprire un visualizzatore tensorboard all'interno di un notebook, copiare il codice seguente in una code-cell:\n",
        "\n",
        "```\n",
        "%tensorboard --logdir {logdir}/regularizers\n",
        "```"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "KX3Voac-FEO4"
      },
      "source": [
        "Potete vedere il [risultato di un'esecuzione precedente](https://tensorboard.dev/experiment/fGInKDo8TXes1z7HQku9mw/#scalars&_smoothingWeight=0.97) di questo notebook su [TensorDoard.dev](https://tensorboard.dev/).\n",
        "\n",
        "Per praticità, esso è anche incluso in un `<iframe>`:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "doMtyYoqFEO5"
      },
      "outputs": [],
      "source": [
        "display.IFrame(\n",
        "    src=\"https://tensorboard.dev/experiment/fGInKDo8TXes1z7HQku9mw/#scalars&_smoothingWeight=0.97\",\n",
        "    width = \"100%\",\n",
        "    height=\"800px\")\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mds5RXGjIcSu"
      },
      "source": [
        "Che è stato caricato con:\n",
        "\n",
        "```\n",
        "!tensorboard dev upload --logdir  {logdir}/regularizers\n",
        "```"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "uXJxtwBWIhjG"
      },
      "source": [
        "## Conclusioni"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "gjfnkEeQyAFG"
      },
      "source": [
        "Ricapitolando: questi sono i modi più comuni per prevenire il sovradattamento nelle reti neurali:\n",
        "\n",
        "* Usare più dati di addestramento.\n",
        "* Ridurre la capacità della rete.\n",
        "* Aggiungere la regolarizzazione del peso.\n",
        "* Aggiungere il dropout.\n",
        "\n",
        "In questa guida non sono trattati due approcci importanti:\n",
        "\n",
        "* l'aumento dei dati\n",
        "* la normalizzazione a lotti\n",
        "\n",
        "Ricordate che ogni metodo è utile in se stesso, ma spesso combinarli può essere più efficace."
      ]
    }
  ],
  "metadata": {
    "accelerator": "GPU",
    "colab": {
      "collapsed_sections": [],
      "name": "overfit_and_underfit.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
